Mark Meyer | Parametric surfaces | rotating sphere

size(550, 550)
background(0)
nofill()
stroke(0.6, 0.6, 0.7, 0.35)
strokewidth(0.5)
translate(WIDTH/2, HEIGHT/2)
# n defines how many vertices we find: the number will be n^2.
# Large values of n can take a while to render!
n = 27
# Define parametric equations for each axis.
# Although we define an z coordinate,
# it is only used in transformations and shading;
# it is not used in the drawing
# (although it could be if you wanted to add perspective).
r = 240
def x(u, v): return r * sin(u) * cos(v)
def y(u, v): return r * sin(u) * sin(v)
def z(u, v): return r * cos(u)
def fit_to_domain(u, v):
u = 1.0 * u / n * pi
v = 1.0 * v / n * pi*2
return u, v
from Numeric import *
def matrix(u, v, index):
u, v = fit_to_domain(u, v)
return where(index==0, x(u, v),
where(index==1, y(u,v),
where(index==2, z(u,v), 1)
)
)
def rotate_matrix(matrix, x, y, z):
rot_x = array(
([1, 0, 0],
[0, cos(x), -sin(x)],
[0, sin(x), cos(x)]
), Float
)
rot_y = array(
([cos(y), 0, sin(y)],
[0, 1, 0],
[-sin(y), 0, cos(y)]
), Float
)
rot_z = array(
([cos(z), -sin(z), 0],
[sin(z), cos(z), 0],
[0, 0, 1]
), Float
)
matrix = matrixmultiply(matrix, rot_x)
matrix = matrixmultiply(matrix, rot_y)
matrix = matrixmultiply(matrix, rot_z)
return matrix
def project(rows):
"""
Go through the array and draw rectangles.
There is probably a more efficent way to do this.
"""
for i in range(len(rows)-1):
for j in range(len(rows[i])-1):
beginpath(
rows[i][j][0],
rows[i][j][1]
)
lineto(
rows[i+1][j][0],
rows[i+1][j][1]
)
lineto(
rows[i+1][j+1][0],
rows[i+1][j+1][1]
)
lineto(
rows[i][j+1][0],
rows[i][j+1][1]
)
endpath()
# Silders to control the rotation.
var("rot_x", NUMBER, 0.0, -pi, pi)
var("rot_y", NUMBER, 0.5, -pi, pi)
var("rot_z", NUMBER, 0.5, -pi, pi)
sphere = fromfunction(matrix, (n+1, n+1, 3))
sphere = rotate_matrix(sphere, rot_x, rot_y, rot_z)
project(sphere)